package it.unica.informatica.enotes;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import com.mobeta.android.dslv.DragSortListView;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;

import it.unica.informatica.enotes.capture.AudioCapture;
import it.unica.informatica.enotes.capture.ImageVideoCapture;
import it.unica.informatica.enotes.database.DatabaseAdapter;
import it.unica.informatica.enotes.manager.AttachmentsAcquisitionManager;
import it.unica.informatica.enotes.manager.AttachmentsStoringManager;
import it.unica.informatica.enotes.manager.NoteSenderManager;
import it.unica.informatica.enotes.manager.NotesManager;
import it.unica.informatica.enotes.notes.AttachmentItem;
import it.unica.informatica.enotes.adapter.MultimediaItemAdapter;
import it.unica.informatica.enotes.notes.Note;
import it.unica.informatica.enotes.adapter.TagItemAdapter;

/**
 * This activity provides the necessary operations to show, modify, delete and send a note
 *
 * @author Mirko Marras
 * @version 1.0
 */
public class NotesActivity extends ActionBarActivity {

   /*********************************************************************************************
    *                                       STATE VARIABLES                                     *
    *********************************************************************************************/

   private static final boolean isInternalMultimediaCapturing = true;
   private DatabaseAdapter databaseAdapter;

   private static final String KEY_CURRENT_NOTE = "current_note";
   private Note currentNote;

   private static final String KEY_NOTE_ID = "note_id";
   private Long currentNoteId;

   private static final String KEY_CURRENT_TAB = "current_tab";
   private static final int[] TAB_IDS = {R.id.action_view_text, R.id.action_view_attachments, R.id.action_view_tags};
   private int currentTab;

   private static final String KEY_EDIT_STATE = "edit_state";
   private boolean editState;

   /*********************************************************************************************
    *                     CONSTANTS FOR INTENT TO REQUEST MULTIMEDIA CONTENT                    *
    *********************************************************************************************/

   private static final int REQUEST_VIEW = 0;

   public static final String TEMP_IMAGE_FILE = "enotes_temp_image.jpg";
   private static final int REQUEST_CAMERA = 1;
   private static final int SELECT_IMAGE = 2;

   public static final String TEMP_VIDEO_FILE = "enotes_temp_video.mp4";
   private static final int REQUEST_VIDEO = 3;
   private static final int SELECT_VIDEO = 4;

   public static final String TEMP_AUDIO_FILE = "enotes_temp_audio.mp3";
   private static final int REQUEST_AUDIO = 5;
   private static final int SELECT_AUDIO = 6;

   /**********************************************************************************************
    *                                 VARIABLES FOR ACTIVITY VIEWS                               *
    **********************************************************************************************/

   private Menu actionBarMenu;

   /* VARIABLES FOR ACTIVITY TABS */
   private Button tabButtonText;
   private Button tabButtonAttachments;
   private Button tabButtonTags;

   /* VARIABLES FOR TEXT CONTENT TAB */
   private ScrollView mainScrollView;
   private EditText titleText;
   private EditText contentText;
   private TextView lastModifiedDate;

   /* VARIABLES FOR ATTACHMENTS TAB */
   private LinearLayout mainAttachmentView;
   private LinearLayout bottomButtons;
   private ArrayList<AttachmentItem> attachments;
   private DragSortListView multimediaDragSortListView;
   private MultimediaItemAdapter multimediaAdapter;
   private TextView emptyAttachmentView;

   /* VARIABLES FOR TAGS TAB */
   private LinearLayout mainTagView;
   private LinearLayout tagLayout;
   private EditText insertTag;
   private ArrayList<String> tags;
   private DragSortListView tagsDragSortListView;
   private TagItemAdapter tagAdapter;
   private TextView emptyTagView;

    /* ********************************************************************************************
     *                         ACTIVITY LIFECYCLE METHODS AND SIMILAR                             *
     **********************************************************************************************/

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_notes);
      getSupportActionBar().setDisplayHomeAsUpEnabled(true);

      /* Create the database used to perform queries */
      databaseAdapter = new DatabaseAdapter(getApplicationContext());
      databaseAdapter.open();

      /* Set the base directory where the app stores temporary files */
      AttachmentsStoringManager.setBaseDirectories(this);

      /* Retrieve state variables for the activity and the note */
      initializeStateVariables(savedInstanceState);

      /* Perform bind from view layout objects to activity variables */
      initializeViews();

      /* Set the content view layout object to the values of the note with the ID retrieved */
      populateFields();

      /* Check if there is an import request */
      if (this.getIntent().getData() != null) {
         new ImportNoteTask(this).execute();
      }
   }

   @Override
   protected void onDestroy() {
      super.onDestroy();

      /* Close the database */
      databaseAdapter.close();
   }

   @Override
   protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);

      /* Save the ID of the current note to retrieve it when the activity is recreated */
      outState.putSerializable(KEY_NOTE_ID, currentNoteId);

      /* Save the EditState of the current note to retrieve it when the activity is recreated */
      outState.putSerializable(KEY_EDIT_STATE, editState);

      /* Save the current tab to retrieve it when the activity is recreated */
      outState.putSerializable(KEY_CURRENT_TAB, currentTab);

      /* Save the current note to retrieve it when the activity is recreated */
      outState.putParcelable(KEY_CURRENT_NOTE, currentNote);

   }

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      actionBarMenu = menu;

      MenuInflater inflater = getMenuInflater();
      inflater.inflate(R.menu.menu_notes, menu);

      /* Disable views based on the state of the activity: EDIT/ONLY VIEW note contents */
      onActivityStateChange();

      return super.onCreateOptionsMenu(menu);
   }

   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
         case android.R.id.home:
            onBackPressed();
            return true;
         case R.id.action_edit:
            /* Activate views to modify note contents */
            editState = true;
            onActivityStateChange();
            return true;
         case R.id.action_save:
            /* Save note content to the database */
            saveNote();
            return true;
         case R.id.action_discard:
            /* Delete the note from the database */
            deleteNote();
            return true;
         case R.id.action_new_email:
            /* Create a file that contains the content of the note and send it by mail */
            sendNoteByEmail();
            return true;
         default:
            return super.onOptionsItemSelected(item);
      }
   }

    /* ********************************************************************************************
     *                           METHODS OF THE ACTION BAR BUTTONS                                *
     **********************************************************************************************/

   /**
    * Return to the MainScreenActivity when the user press the back button from this activity
    */
   @Override
   public void onBackPressed() {
      if (editState && !currentNote.isEmpty()) {
         new SaveTask(this, true).execute();
      } else {
         if(currentNote.getId() == AttachmentsStoringManager.CREATE_PREFIX &&
           (currentNote.getAttachments().size() > 0 || currentNote.getTags().size() > 0) ) {
            Toast.makeText(getBaseContext(), R.string.toast_empty_note, Toast.LENGTH_SHORT).show();
         }
         else {
            super.onBackPressed();
         }
      }
   }

   /**
    * Delete the current note from the database if exists or discard it if it is a draft
    */
   private void deleteNote() {
      /* Verify if the note contains some data and delete it if it is already saved into the database  */
      if (!currentNote.isEmpty() || currentNote.getAttachments().size() > 0 || currentNote.getTags().size() > 0) {

         /* Create and show a dialog to ask a confirm from the user */
         AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setTitle(R.string.action_delete_dialog_title);
         builder.setMessage(R.string.action_delete_dialog_message);

         builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
               /* If the note already exists, it is deleted from the database */
               if (currentNoteId != null) {
                  NotesManager.deleteNoteById(databaseAdapter, currentNote.getId());
                  Toast.makeText(getBaseContext(), R.string.toast_delete_note, Toast.LENGTH_SHORT).show();
               } else { /* If the note doesn't exists and it is only a draft */
                  AttachmentsStoringManager.deleteDirAppMemory(AttachmentsStoringManager.CREATE_PREFIX);
                  Toast.makeText(getBaseContext(), R.string.toast_delete_draft, Toast.LENGTH_SHORT).show();
               }

               finish();
            }
         });

         builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
            }
         });

         builder.show();

      } else {
         finish();
      }

   }

   /**
    * Create and start an intent to send an email with a note contents file as attachment
    */
   private void sendNoteByEmail() {
      /* Verify if the note contains some data and create an email intent to send it */
      if (!currentNote.isEmpty()) {
         new ExportNoteTask(this).execute();
      } else { /* If the note doesn't contain any data */
         Toast.makeText(getBaseContext(), R.string.toast_empty_note, Toast.LENGTH_SHORT).show();
      }
   }

   /**
    * Save the current note to the database
    */
   private void saveNote() {
      if (!currentNote.isEmpty()) {
         new SaveTask(this, false).execute();
      } else {
         Toast.makeText(getBaseContext(), R.string.toast_empty_note, Toast.LENGTH_SHORT).show();
      }
   }

    /* ********************************************************************************************
     *        METHODS ASSOCIATED WITH AN ON CLICK LISTENER FOR BUTTONS IN THE LAYOUT              *
     **********************************************************************************************/

   /**
    * Show or hide view objects of the layout based on the tab button selected by the user
    *
    * @param v The tab button selected by the user
    */
   public void onTabButtonSelected(View v) {
      int disableColor = Color.argb(0xff, 0x80, 0x80, 0x80);
      int activeColor = Color.argb(0xff, 0x3b, 0x59, 0x98);

      /* Perform a selection based on the clicked tab: TEXT CONTENT, ATTACHMENTS and TAGS tabs */
      switch (v.getId()) {

         /*************************** CURRENT TAB: TEXT CONTENT ********************************/
         case R.id.action_view_text:
            currentTab = TAB_IDS[0];

            /* Color to blue the TEXT CONTENT tab button and color to grey other tab buttons */
            tabButtonText.setSelected(true);
            tabButtonText.setTextColor(activeColor);
            tabButtonAttachments.setSelected(false);
            tabButtonAttachments.setTextColor(disableColor);
            tabButtonTags.setSelected(false);
            tabButtonTags.setTextColor(disableColor);

            /* Set to VISIBLE the EditTexts for the title and the text content of the note */
            mainScrollView.setVisibility(View.VISIBLE);

            /* Set to GONE the views for the ATTACHMENTS tab and the TAGS tab */
            mainAttachmentView.setVisibility(View.GONE);
            bottomButtons.setVisibility(View.GONE);
            tagLayout.setVisibility(View.GONE);
            mainTagView.setVisibility(View.GONE);
            break;

         /*************************** CURRENT TAB: ATTACHMENTS *********************************/
         case R.id.action_view_attachments:
            currentTab = TAB_IDS[1];

            /* Color to blue the ATTACHMENTS tab button and color to grey other tab buttons */
            tabButtonText.setSelected(false);
            tabButtonText.setTextColor(disableColor);
            tabButtonAttachments.setSelected(true);
            tabButtonAttachments.setTextColor(activeColor);
            tabButtonTags.setSelected(false);
            tabButtonTags.setTextColor(disableColor);

            /* Set to GONE the views for the TEXT CONTENT tab */
            mainScrollView.setVisibility(View.GONE);

            /* Set to VISIBLE the view for the ATTACHMENTS tab */
            mainAttachmentView.setVisibility(View.VISIBLE);
            bottomButtons.setVisibility((editState) ? View.VISIBLE : View.GONE);

            /* Set to GONE the views for the TAGS tab */
            tagLayout.setVisibility(View.GONE);
            mainTagView.setVisibility(View.GONE);
            break;

         /********************************* CURRENT TAB: TAGS **********************************/
         case R.id.action_view_tags:
            currentTab = TAB_IDS[2];

            /* Color to blue the TAGS tab button and color to grey other tab buttons */
            tabButtonText.setSelected(false);
            tabButtonText.setTextColor(disableColor);
            tabButtonAttachments.setSelected(false);
            tabButtonAttachments.setTextColor(disableColor);
            tabButtonTags.setSelected(true);
            tabButtonTags.setTextColor(activeColor);

            /* Set to GONE the views for the TEXT CONTENT tab and the ATTACHMENTS tab */
            mainScrollView.setVisibility(View.GONE);
            mainAttachmentView.setVisibility(View.GONE);
            bottomButtons.setVisibility(View.GONE);

            /* Set to VISIBLE the view for the TAGS tab */
            tagLayout.setVisibility((editState) ? View.VISIBLE : View.GONE);
            mainTagView.setVisibility(View.VISIBLE);
            break;
         default:
      }

      /* Hide the software keyboard to prevent changes when the activity pass to the EDIT state */
      if (titleText != null && contentText != null) {
         InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
         inputMethodManager.hideSoftInputFromWindow(titleText.getWindowToken(), 0);
         inputMethodManager.hideSoftInputFromWindow(contentText.getWindowToken(), 0);
      }
   }

   /**
    * Show a specific intent to take a multimedia content based on the button selected by the user
    *
    * @param v The button associated to a type of multimedia content (Image, Audio, Video)
    */
   public void onInsertAttachmentSelected(View v) {
      switch (v.getId()) {
         case R.id.action_camera:
            /* Show a dialog to choose how to take an IMAGE from the device */
            onSelectImageRequest();
            break;
         case R.id.action_mic:
            /* Show a dialog to choose how to take an AUDIO TRACK from the device */
            onSelectAudioRequest();
            break;
         case R.id.action_video:
            /* Show a dialog to choose how to take a VIDEO from the device */
            onSelectVideoRequest();
            break;
         default:
      }
   }

   /**
    * Add the tag inserted by the user to the tags list for the current note
    *
    * @param v The button clicked by the user to add a new tag
    */
   public void onInsertTagSelected(View v) {
      /* Read the tag inserted by the user and transform it to lower case */
      String readTag = insertTag.getText().toString().toLowerCase();

      /* If the tag is a single word with at least one letter, add the tag to the tags list */
      if (!tags.contains(readTag)) {

         if (readTag.length() > 0 && !readTag.contains(" ")) {
            tags.add(0, readTag);
            tagAdapter.notifyDataSetChanged();

            insertTag.setText("");
            tabButtonTags.setText(tabButtonTags.getTag() + " (" + tags.size() + ")");
            Toast.makeText(getBaseContext(), R.string.toast_tag_inserted, Toast.LENGTH_SHORT).show();

         } else { /* If the tag string is empty or contains more than one word */
            Toast.makeText(getBaseContext(), R.string.toast_tag_error, Toast.LENGTH_SHORT).show();
         }
      } else { /* If the tag string already exists in the list */
         Toast.makeText(getBaseContext(), R.string.toast_tag_duplicate, Toast.LENGTH_SHORT).show();
      }
   }

   /**
    * Sort the tags list in lessico-order, unless when the user can perform custom sort
    *
    * @param v The button clicked by the user to sort the tags list
    */
   public void onSortTagsPressed(View v) {
      /* Create and show a dialog to ask a confirm from the user */
      AlertDialog.Builder builder = new AlertDialog.Builder(this);
      builder.setTitle(R.string.action_sort_dialog_title);
      builder.setMessage(R.string.action_sort_dialog_message);

      builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int id) {
            Collections.sort(tags);
            tagAdapter.notifyDataSetChanged();
            Toast.makeText(getBaseContext(), R.string.action_sort_dialog_correct, Toast.LENGTH_SHORT).show();
         }
      });

      builder.setNegativeButton(R.string.cancel_button, new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int id) {
         }
      });

      builder.show();
   }

   /**
    * Show a dialog to allow the user to select how to take a new image as attachment for the current note
    */
   private void onSelectImageRequest() {
      /* Set the title of the available choices to take an image from the device */
      final String[] items = {getString(R.string.action_camera_dialog_camera),
              getString(R.string.action_camera_dialog_library)};

      /* Create and show a dialog with which the user selects the method to take the image */
      AlertDialog.Builder builder = new AlertDialog.Builder(NotesActivity.this);
      builder.setTitle(getString(R.string.action_camera_dialog_title) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_IMAGE_MB + ")");

      builder.setItems(items, new DialogInterface.OnClickListener() {
         @Override
         public void onClick(DialogInterface dialog, int item) {
            /* If the user selects to take an image by the device camera */
            if (items[item].equals(getString(R.string.action_camera_dialog_camera))) {

               if(isInternalMultimediaCapturing) {
                  Intent intent = new Intent(getApplicationContext(), ImageVideoCapture.class);
                  intent.putExtra(ImageVideoCapture.EXTRA_OUTPUT, android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +  TEMP_IMAGE_FILE);
                  intent.putExtra(ImageVideoCapture.EXTRA_ACTION, ImageVideoCapture.IMAGE_CAPTURE);
                  startActivityForResult(intent, REQUEST_CAMERA);
               }
               else {
                  Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                  File f = new File(android.os.Environment.getExternalStorageDirectory(), TEMP_IMAGE_FILE);

                  intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));

                  if (intent.resolveActivity(getPackageManager()) != null) {
                     startActivityForResult(intent, REQUEST_CAMERA);
                  } else {
                     Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
                  }
               }
            /* If the user selects to pick an image from another application of the device */
            } else if (items[item].equals(getString(R.string.action_camera_dialog_library))) {
               Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
               intent.setType("image/*");

               if (intent.resolveActivity(getPackageManager()) != null) {
                  startActivityForResult(Intent.createChooser(intent, getString(R.string.action_camera_dialog_title)), SELECT_IMAGE);
               } else {
                  Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
               }
            }
         }
      });

      builder.show();
   }

   /**
    * Show a dialog to allow the user to select how to take a new video as attachment for the current note
    */
   private void onSelectVideoRequest() {
      /* Set the title of the available choices to take a video from the device */
      final String[] items = {getString(R.string.action_video_dialog_camera),
              getString(R.string.action_video_dialog_library)};

      /* Create and show a dialog with which the user selects the method to take the video */
      AlertDialog.Builder builder = new AlertDialog.Builder(NotesActivity.this);
      builder.setTitle(getString(R.string.action_video_dialog_title)
              + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_MB
              + " - " + AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_SEC + ")");

      builder.setItems(items, new DialogInterface.OnClickListener() {
         @Override
         public void onClick(DialogInterface dialog, int item) {
            /* If the user selects to take a video by the device camera */
            if (items[item].equals(getString(R.string.action_video_dialog_camera))) {
               if(isInternalMultimediaCapturing) {
                  Intent intent = new Intent(getApplicationContext(), ImageVideoCapture.class);
                  intent.putExtra(ImageVideoCapture.EXTRA_OUTPUT, android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + TEMP_VIDEO_FILE);
                  intent.putExtra(ImageVideoCapture.EXTRA_ACTION, ImageVideoCapture.VIDEO_CAPTURE);
                  startActivityForResult(intent, REQUEST_VIDEO);
               }
               else {
                  Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
                  File f = new File(android.os.Environment.getExternalStorageDirectory(), TEMP_VIDEO_FILE);

                  /* Set acquisition parameters: low resolution, duration and size limits */
                  intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
                  intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
                  intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_SEC);
                  intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_BYTE);

                  if (intent.resolveActivity(getPackageManager()) != null) {
                     startActivityForResult(intent, REQUEST_VIDEO);
                  } else {
                     Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
                  }
               }
             /* If the user selects to pick a video from another application of the device */
            } else if (items[item].equals(getString(R.string.action_video_dialog_library))) {
               Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
               intent.setType("video/*");

               if (intent.resolveActivity(getPackageManager()) != null) {
                  startActivityForResult(Intent.createChooser(intent, getString(R.string.action_video_dialog_title)), SELECT_VIDEO);
               } else {
                  Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
               }
            }
         }
      });

      builder.show();
   }

   /**
    * Show a dialog to allow the user to select how to take a new audio track as attachment for the current note
    */
   private void onSelectAudioRequest() {
      /* Set the title of the available choices to take a video from the device */
      final String[] items = {getString(R.string.action_audio_dialog_audio),
              getString(R.string.action_audio_dialog_library)};

      /* Create and show a dialog with which the user selects the method to take the audio track */
      AlertDialog.Builder builder = new AlertDialog.Builder(NotesActivity.this);
      builder.setTitle(getString(R.string.action_audio_dialog_title)
              + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_AUDIO_MB
              + " - " + AttachmentsAcquisitionManager.ALLOWED_MAX_AUDIO_SEC + ")");

      builder.setItems(items, new DialogInterface.OnClickListener() {
         @Override
         public void onClick(DialogInterface dialog, int item) {
            /* If the user selects to take an audio track by the device recorder */
            if (items[item].equals(getString(R.string.action_audio_dialog_audio))) {
               if(isInternalMultimediaCapturing) {
                  Intent intent = new Intent(getApplicationContext(), AudioCapture.class);
                  intent.putExtra(AudioCapture.EXTRA_OUTPUT, android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +  TEMP_AUDIO_FILE);
                  intent.putExtra(AudioCapture.EXTRA_ACTION, AudioCapture.RECORD_SOUND_ACTION);
                  startActivityForResult(intent, REQUEST_AUDIO);
               }
               else {
                  Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);

                  if (intent.resolveActivity(getPackageManager()) != null) {
                     startActivityForResult(intent, REQUEST_AUDIO);
                  } else {
                     Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
                  }
               }
            /* If the user selects to pick an audio track from another application of the device */
            } else if (items[item].equals(getString(R.string.action_audio_dialog_library))) {
               Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
               intent.setType("audio/*");

               if (intent.resolveActivity(getPackageManager()) != null) {
                  startActivityForResult(Intent.createChooser(intent, getString(R.string.action_audio_dialog_title)), SELECT_AUDIO);
               } else {
                  Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
               }
            }
         }
      });

      builder.show();
   }

    /* ********************************************************************************************
     *               METHODS FOR INITIALIZATION AND SETTING OF THE LAYOUT COMPONENTS              *
     **********************************************************************************************/

   /**
    * Enable or disable controls to modify the current note based on the current EditState: ONLY VIEW or EDIT
    */
   public void onActivityStateChange() {
      /* Set the correct action bar icon to visible based on activity state: EDIT/ONLY VIEW */
      actionBarMenu.findItem(R.id.action_edit).setVisible(!editState);
      actionBarMenu.findItem(R.id.action_save).setVisible(editState);

      /* Set EditTexts of the note contents to Editable based on activity state: EDIT/ONLY VIEW */
      titleText.setFocusableInTouchMode(editState);
      titleText.setFocusable(editState);
      contentText.setFocusableInTouchMode(editState);
      contentText.setFocusable(editState);

      /* Recreate attachments DragSortListView  to show edit commands based on activity state: EDIT/ONLY VIEW */
      multimediaAdapter = new MultimediaItemAdapter(this, currentNote, tabButtonAttachments, editState, attachments);
      multimediaDragSortListView.setAdapter(multimediaAdapter);
      multimediaDragSortListView.setDragEnabled(editState);
      multimediaDragSortListView.setRemoveEnabled(editState);
      bottomButtons.setVisibility((editState && mainAttachmentView.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE);

      /* Recreate tags DragSortListView  to show edit commands based on activity state: EDIT/ONLY VIEW */
      tagAdapter = new TagItemAdapter(this, tabButtonTags, editState, tags);
      tagsDragSortListView.setAdapter(tagAdapter);
      tagsDragSortListView.setDragEnabled(editState);
      tagsDragSortListView.setRemoveEnabled(editState);
      tagLayout.setVisibility((editState && mainTagView.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE);

      /* Hide the software keyboard to prevent changes when the activity pass to the EDIT state */
      InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
      inputMethodManager.hideSoftInputFromWindow(titleText.getWindowToken(), 0);
      inputMethodManager.hideSoftInputFromWindow(contentText.getWindowToken(), 0);
   }

   /**
    * Initialize the variables that store the current state for the activity, for example, the ID of the current note
    *
    * @param savedInstanceState The state of the variables if the activity is destroyed by the system
    */
   public void initializeStateVariables(Bundle savedInstanceState) {

      /* Verify if there is an instance state for a note and take its ID if exists */
      if (savedInstanceState == null) {
         currentNoteId = null;
      } else {
         currentNoteId = (Long) savedInstanceState.getSerializable(KEY_NOTE_ID);
         editState = (Boolean) savedInstanceState.getSerializable(KEY_EDIT_STATE);
      }

      /* Verify if it is received an intent to open a note from the Main Activity, take its ID from extras */
      if (currentNoteId == null) {
         Bundle extras = getIntent().getExtras();
         currentNoteId = extras != null ? extras.getLong(MainScreenActivity.NOTE_ID) : null;
      }

      /* Verify if there is an instance state for a note and take its EditState if exists */
      if (savedInstanceState == null) {
         editState = (currentNoteId == null) ? true : false;
      } else {
         editState = (Boolean) savedInstanceState.getSerializable(KEY_EDIT_STATE);
      }

      /* Verify if there is an instance state for a note and take its current tab if exists */
      if (savedInstanceState == null) {
         currentTab = TAB_IDS[0];
      } else {
         currentTab = (Integer) savedInstanceState.getSerializable(KEY_CURRENT_TAB);
      }

      /* Retrieve a note from the database by its ID if set or create an empty note */
      if (savedInstanceState == null) {
         currentNote = (currentNoteId == null) ? new Note() : NotesManager.getNoteById(databaseAdapter, currentNoteId);

         /* If the activity is initialized to create a new note delete if exists the old default directory */
         if(currentNoteId == null && this.getIntent().getData() == null) {
            AttachmentsStoringManager.deleteDirAppMemory(AttachmentsStoringManager.CREATE_PREFIX);
         }

      } else {
         currentNote = (Note) savedInstanceState.getParcelable(KEY_CURRENT_NOTE);
      }
   }

   /**
    * Bind view object with the views of the layout and initialize their listeners and base properties
    */
   private void initializeViews() {

      /* Show the content associated to the current tab */
      tabButtonText = (Button) findViewById(R.id.action_view_text);
      tabButtonAttachments = (Button) findViewById(R.id.action_view_attachments);
      tabButtonTags = (Button) findViewById(R.id.action_view_tags);
      mainScrollView = (ScrollView) findViewById(R.id.mainScrollView);
      mainAttachmentView = (LinearLayout) findViewById(R.id.mainAttachmentView);
      mainTagView = (LinearLayout) findViewById(R.id.mainTagView);
      tagLayout = (LinearLayout) findViewById(R.id.tagLayout);
      bottomButtons = (LinearLayout) findViewById(R.id.bottomButtons);

      Button tabButton = new Button(this);
      tabButton.setId(currentTab);
      onTabButtonSelected(tabButton);

      /* Initialize EditText used to write the note title and take its contents after change */
      titleText = (EditText) findViewById(R.id.titleText);

      titleText.addTextChangedListener(new TextWatcher() {
         public void afterTextChanged(Editable s) {
            currentNote.setTitle(titleText.getText().toString());
         }

         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
         }

         public void onTextChanged(CharSequence s, int start, int before, int count) {
         }
      });

      /* Initialize EditText used to write the note text content and take its contents after change */
      contentText = (EditText) findViewById(R.id.contentText);

      contentText.addTextChangedListener(new TextWatcher() {
         public void afterTextChanged(Editable s) {
            currentNote.setContent(contentText.getText().toString());
         }

         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
         }

         public void onTextChanged(CharSequence s, int start, int before, int count) {
         }
      });

      contentText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
         public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
               contentText.setText(Html.fromHtml(contentText.getText().toString()));
               contentText.setMovementMethod(LinkMovementMethod.getInstance());
               currentNote.setContent(contentText.getText().toString());
            }
         }
      });

      /* Initialize TextView used to write the date of the last change of the note content */
      lastModifiedDate = (TextView) findViewById(R.id.lastModifiedDate);

      /* Initialize DragSortListView  for the note attachments and set the onClick listener to view them */
      emptyAttachmentView = (TextView) findViewById(R.id.emptyAttachmentView);

      multimediaDragSortListView = (DragSortListView) findViewById(R.id.attachmentsDragSortListView);
      multimediaDragSortListView.setEmptyView(emptyAttachmentView);

      multimediaDragSortListView.setDropListener(new DragSortListView.DropListener() {
         @Override
         public void drop(int from, int to) {
            AttachmentItem item = multimediaAdapter.getItem(from);
            multimediaAdapter.remove(from);
            multimediaAdapter.insert(item, to);
            multimediaAdapter.notifyDataSetChanged();
         }
      });

      multimediaDragSortListView.setRemoveListener(new DragSortListView.RemoveListener() {
         @Override
         public void remove(int which) {
            AttachmentsStoringManager.deleteFromAppMemory(multimediaAdapter.getItem(which).getName(), currentNote.getId());
            multimediaAdapter.remove(which);
            tabButtonAttachments.setText(tabButtonAttachments.getTag() + " (" + attachments.size() + ")");
         }
      });

      multimediaDragSortListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            AttachmentItem selectedAttachment = attachments.get(position);
            Uri attachmentUri = Uri.fromFile(AttachmentsStoringManager.getAttachmentFile(currentNote.getId(), selectedAttachment));
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.setDataAndType(attachmentUri, selectedAttachment.getType());
            if (intent.resolveActivity(getPackageManager()) != null) {
               startActivityForResult(intent, REQUEST_VIEW);
            } else {
               Toast.makeText(getBaseContext(), R.string.toast_no_intent, Toast.LENGTH_SHORT).show();
            }
         }
      });

      /* Initialize DragSortListView for the note tags */
      emptyTagView = (TextView) findViewById(R.id.emptyTagView);
      tagsDragSortListView = (DragSortListView) findViewById(R.id.tagsDragSortListView);
      tagsDragSortListView.setEmptyView(emptyTagView);
      insertTag = (EditText) findViewById(R.id.insertTag);

      insertTag.setOnKeyListener(new View.OnKeyListener() {
         public boolean onKey(View v, int keyCode, KeyEvent event) {
            if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
               onInsertTagSelected(new Button(getApplicationContext()));
               return true;
            }
            return false;
         }
      });

      tagsDragSortListView.setDropListener(new DragSortListView.DropListener() {
         @Override
         public void drop(int from, int to) {
            String item = (String) tagAdapter.getItem(from);
            tagAdapter.remove(from);
            tagAdapter.insert(item, to);
            tagAdapter.notifyDataSetChanged();
         }
      });

      tagsDragSortListView.setRemoveListener(new DragSortListView.RemoveListener() {
         @Override
         public void remove(int which) {
            tagAdapter.remove(which);
            tabButtonTags.setText(tabButtonTags.getTag() + " (" + tags.size() + ")");
         }
      });
   }

   /**
    * Set the content of the view objects with the values associated to the current note
    */
   private void populateFields() {
      /* Set the action bar title based on the note title */
      String title = (currentNoteId == null) ? getString(R.string.action_add_note) : currentNote.getTitle();
      setTitle(title);

      /* Set the EditTexts content to the note title and the note text content */
      titleText.setText(currentNote.getTitle());
      contentText.setText(Html.fromHtml(currentNote.getContent()));
      contentText.setMovementMethod(LinkMovementMethod.getInstance());

      /* Set the date of the last change of the note */
      String lastChange = (currentNoteId == null) ? "" : getString(R.string.last_date_modified_message) + " " + currentNote.getLastChangeFormatter();
      lastModifiedDate.setText(lastChange);

      /* Set the DragSortListView  of the note attachments based on the attachment of the retrieved note */
      attachments = currentNote.getAttachments();
      multimediaAdapter = new MultimediaItemAdapter(this, currentNote, tabButtonAttachments, editState, attachments);
      multimediaDragSortListView.setAdapter(multimediaAdapter);
      tabButtonAttachments.setText(tabButtonAttachments.getTag() + " (" + attachments.size() + ")");

      /* Set the DragSortListView  of the note tags based on the tags of the retrieved note */
      tags = currentNote.getTags();
      tagAdapter = new TagItemAdapter(this, tabButtonTags, editState, tags);
      tagsDragSortListView.setAdapter(tagAdapter);
      tabButtonTags.setText(tabButtonTags.getTag() + " (" + tags.size() + ")");
   }

    /* ********************************************************************************************
     *                              RESULTS FROM OTHER ACTIVITIES                                 *
     **********************************************************************************************/

   /**
    * Receive the result of an intent send by this activity to an external application
    *
    * @param requestCode The code of the request send by this activity
    * @param resultCode  The code of the result send by the external application
    * @param data        Extra data send by the external application as result
    */
   @Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      if (resultCode == RESULT_OK) {

         /* Check if the SD card is mounted */
         if (AttachmentsAcquisitionManager.isExternalStorageWritable()) {

            /* Declare the variable to store the received attachment */
            AttachmentItem resultAttachment = null;
            String positiveMessage = null;
            String negativeExtensionMessage = null;
            String negativeMaxSizeMessage = null;
            String negativeDurationMessage = null;

            switch (requestCode) {
               case REQUEST_CAMERA: /* Receive an image obtained by the device camera */
                  resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromFile(NotesActivity.this,
                          currentNote.getId(),
                          TEMP_IMAGE_FILE,
                          AttachmentItem.TYPE_IMAGE);

                  positiveMessage = getString(R.string.toast_insert_image_attachment);
                  negativeExtensionMessage = getString(R.string.toast_image_not_supported_ext);
                  negativeMaxSizeMessage = getString(R.string.toast_image_not_supported_size) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_IMAGE_MB + ")";
                  break;
               case SELECT_IMAGE: /* Receive an image picked from an external application */
                  resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromUri(NotesActivity.this,
                          currentNote.getId(),
                          data.getData(),
                          AttachmentItem.TYPE_IMAGE);

                  positiveMessage = getString(R.string.toast_insert_image_attachment);
                  negativeExtensionMessage = getString(R.string.toast_image_not_supported_ext);
                  negativeMaxSizeMessage = getString(R.string.toast_image_not_supported_size) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_IMAGE_MB + ")";
                  break;
               case REQUEST_VIDEO: /* Receive a video obtained by the device camera */
                  resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromFile(NotesActivity.this,
                          currentNote.getId(),
                          TEMP_VIDEO_FILE,
                          AttachmentItem.TYPE_VIDEO);

                  positiveMessage = getString(R.string.toast_insert_video_attachment);
                  negativeExtensionMessage = getString(R.string.toast_video_not_supported_ext);
                  negativeMaxSizeMessage = getString(R.string.toast_video_not_supported_size) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_MB + ")";
                  negativeDurationMessage = getString(R.string.toast_video_not_supported_duration) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_SEC + ")";
                  break;
               case SELECT_VIDEO: /* Receive a video picked from an external application */
                  resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromUri(NotesActivity.this,
                          currentNote.getId(),
                          data.getData(),
                          AttachmentItem.TYPE_VIDEO);

                  positiveMessage = getString(R.string.toast_insert_video_attachment);
                  negativeExtensionMessage = getString(R.string.toast_video_not_supported_ext);
                  negativeMaxSizeMessage = getString(R.string.toast_video_not_supported_size) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_MB + ")";
                  negativeDurationMessage = getString(R.string.toast_video_not_supported_duration) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_VIDEO_SEC + ")";
                  break;
               case REQUEST_AUDIO: /* Receive an audio track obtained by the device recorder */
                  if(isInternalMultimediaCapturing) {
                     resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromFile(
                             NotesActivity.this,
                             currentNote.getId(),
                             TEMP_AUDIO_FILE,
                             AttachmentItem.TYPE_AUDIO);
                  }
                  else {
                     resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromUri(NotesActivity.this,
                             currentNote.getId(),
                             data.getData(),
                             AttachmentItem.TYPE_AUDIO);
                  }

                  positiveMessage = getString(R.string.toast_insert_audio_attachment);
                  negativeExtensionMessage = getString(R.string.toast_audio_not_supported_ext);
                  negativeMaxSizeMessage = getString(R.string.toast_audio_not_supported_size) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_AUDIO_MB + ")";
                  negativeDurationMessage = getString(R.string.toast_audio_not_supported_duration) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_AUDIO_SEC + ")";
                  break;
               case SELECT_AUDIO: /* Receive an audio track picked from an external application */
                  resultAttachment = AttachmentsAcquisitionManager.getAttachmentFromUri(NotesActivity.this,
                             currentNote.getId(),
                             data.getData(),
                             AttachmentItem.TYPE_AUDIO);

                  positiveMessage = getString(R.string.toast_insert_audio_attachment);
                  negativeExtensionMessage = getString(R.string.toast_audio_not_supported_ext);
                  negativeMaxSizeMessage = getString(R.string.toast_audio_not_supported_size) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_AUDIO_MB + ")";
                  negativeDurationMessage = getString(R.string.toast_audio_not_supported_duration) + " (" + AttachmentsAcquisitionManager.ALLOWED_MAX_AUDIO_SEC + ")";
                  break;
               default:
            }

            /* Verify if the attachment is received without errors */
            if (resultAttachment.getState() == AttachmentItem.STATE_VALID) {
               attachments.add(0, resultAttachment);
               multimediaAdapter.notifyDataSetChanged();
               tabButtonAttachments.setText(tabButtonAttachments.getTag() + " (" + attachments.size() + ")");
               Toast.makeText(getBaseContext(), positiveMessage, Toast.LENGTH_SHORT).show();
            /* If the received attachment is with not supported extension */
            } else if (resultAttachment.getState() == AttachmentItem.STATE_EXTENSION_ERROR) {
               Toast.makeText(getBaseContext(), negativeExtensionMessage, Toast.LENGTH_SHORT).show();
            /* If the received attachment is with not supported size */
            } else if (resultAttachment.getState() == AttachmentItem.STATE_SIZE_ERROR) {
               Toast.makeText(getBaseContext(), negativeMaxSizeMessage, Toast.LENGTH_SHORT).show();
            /* If the received attachment is with not supported duration */
            } else if (resultAttachment.getState() == AttachmentItem.STATE_DURATION_ERROR) {
               Toast.makeText(getBaseContext(), negativeDurationMessage, Toast.LENGTH_SHORT).show();
            }

         } else { /* If the SD card isn't mounted */
            Toast.makeText(getBaseContext(), R.string.toast_media_not_mounted, Toast.LENGTH_SHORT).show();
         }

      }
   }

    /* ********************************************************************************************
     *                              ASYNC TASKS FOR FAT OPERATIONS                                *
     **********************************************************************************************/

   /**
    * This private class save the note content into the database
    *
    * @author Mirko Marras
    * @version 1.0
    */
   private class SaveTask extends AsyncTask<Void, Void, Boolean> {

      private ProgressDialog dialog;
      private NotesActivity activity;
      private boolean isBackButton;

      public SaveTask(NotesActivity activity, Boolean isBackButton) {
         this.activity = activity;
         this.isBackButton = isBackButton;
         this.dialog = new ProgressDialog(this.activity);
      }

      protected void onPreExecute() {
         this.dialog.setMessage(getString(R.string.progress_save_message));
         this.dialog.setCancelable(false);
         this.dialog.show();
      }

      @Override
      protected void onPostExecute(final Boolean success) {
         if (dialog.isShowing()) {
            dialog.dismiss();
         }

         if (success) {

            /* If the note contains data to save, saves it and returns to the ONLY VIEW state */
            if (!currentNote.isEmpty()) {
               /* Show the new title for the note */
               setTitle(titleText.getText().toString());

               /* Show the new date of the last change for the note */
               lastModifiedDate.setText(getString(R.string.last_date_modified_message) + " " + NotesManager.getNoteById(databaseAdapter, currentNoteId).getLastChangeFormatter());

               Toast.makeText(getBaseContext(), R.string.toast_save_note, Toast.LENGTH_SHORT).show();
            }

            editState = false;
            onActivityStateChange();

            /* Check if after the save the app return to the notes list, otherwise change EditState */
            if (this.isBackButton) {
               onBackPressed();
            }
         } else {
            Toast.makeText(getBaseContext(), R.string.out_of_memory_message, Toast.LENGTH_SHORT).show();
         }

      }

      protected Boolean doInBackground(final Void... args) {
         /* Verify if the note contains some data and create it or save it if exists */
         if (!currentNote.isEmpty()) {

            try {
               /* Verify if the note is already saved into the database, if not create it */
               if (currentNoteId == null) {
                  currentNoteId = NotesManager.createNote(databaseAdapter, currentNote, AttachmentsStoringManager.CREATE_PREFIX);
                  currentNote.setId(currentNoteId);
               } else { /* If the note already exists into the database */
                  NotesManager.updateNote(databaseAdapter, currentNote);
               }
            } catch (Exception exception) {
               return false;
            }
         }
         return true;
      }
   }

   /**
    * This private class import the file that encode a note into the database
    *
    * @author Mirko Marras
    * @version 1.0
    */
   private class ImportNoteTask extends AsyncTask<Void, Void, Boolean> {

      private ProgressDialog dialog;
      private NotesActivity activity;

      public ImportNoteTask(NotesActivity activity) {
         this.activity = activity;
         this.dialog = new ProgressDialog(this.activity);
      }

      protected void onPreExecute() {
         this.dialog.setMessage(getString(R.string.progress_import_message));
         this.dialog.setCancelable(false);
         this.dialog.show();
      }

      @Override
      protected void onPostExecute(final Boolean success) {
         if (success) {
            /* Update the content of the views to show the content of the imported note*/
            populateFields();

            if (dialog.isShowing()) {
               dialog.dismiss();
            }

            Toast.makeText(getBaseContext(), R.string.toast_import_ok, Toast.LENGTH_SHORT).show();
         } else {
            Toast.makeText(getBaseContext(), R.string.toast_import_no, Toast.LENGTH_SHORT).show();
            finish();
         }
      }

      protected Boolean doInBackground(final Void... args) {
         try {
            /* If the activity is started by another application that requests a note import, retrieve and save it*/
            if (this.activity.getIntent().getData() != null) {
               String filePath = NoteSenderManager.getPathToImport(this.activity);
               currentNoteId = NotesManager.createNote(databaseAdapter, NoteSenderManager.getNoteFromMail(filePath), AttachmentsStoringManager.IMPORT_PREFIX);
               currentNote = NotesManager.getNoteById(databaseAdapter, currentNoteId);
            }
         } catch (Exception e) {
            return false;
         }

         return true;
      }

   }

   /**
    * This private class export the note content to send it by email
    *
    * @author Mirko Marras
    * @version 1.0
    */
   private class ExportNoteTask extends AsyncTask<Void, Void, File> {

      private ProgressDialog dialog;
      private NotesActivity activity;

      public ExportNoteTask(NotesActivity activity) {
         this.activity = activity;
         this.dialog = new ProgressDialog(this.activity);
      }

      protected void onPreExecute() {
         this.dialog.setMessage(getString(R.string.progress_export_message));
         this.dialog.setCancelable(false);
         this.dialog.show();
      }

      @Override
      protected void onPostExecute(final File mailAttach) {
         if (dialog.isShowing()) {
            dialog.dismiss();
         }

         /* Check if the file that contains the note in JSON format is founded */
         if (mailAttach != null) {
            Intent intent = new Intent(Intent.ACTION_SEND);
            intent.setType("message/rfc822");
            intent.putExtra(Intent.EXTRA_SUBJECT, currentNote.getTitle());
            intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.action_mail_dialog_message));
            intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(mailAttach));
            if (intent.resolveActivity(getPackageManager()) != null) {
               startActivity(Intent.createChooser(intent, getString(R.string.action_mail_dialog_title)));
            }
            else {
               Toast.makeText(getBaseContext(), R.string.toast_export_no, Toast.LENGTH_SHORT).show();
            }
         } else {
            Toast.makeText(getBaseContext(), R.string.toast_export_no, Toast.LENGTH_SHORT).show();
         }
      }

      protected File doInBackground(final Void... args) {
         File mailAttach;

         try {
            mailAttach = NoteSenderManager.setFileForMail(currentNote);
            if(!mailAttach.exists()) {
               return null;
            }
         } catch (Exception e) {
            return null;
         }

         return mailAttach;
      }

   }

}